﻿using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using MyCompanyName.AbpZeroTemplate.Prm.Admin.QuanDto;
using MyCompanyName.AbpZeroTemplate.Prm.Project;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyCompanyName.AbpZeroTemplate.Prm.Admin
{
    public class QuanAppService : AbpZeroTemplateAppServiceBase, IQuanAppService
    {
        private readonly IRepository<Quan, int> _quanRepository;
        private readonly IRepository<UserQuan, int> _userQuanRepository;
        private readonly IRepository<ProjectQuan, int> _projectQuanRepository;
        private readonly IRepository<TaskQuan, int> _taskQuanRepository;
        private readonly ProjectManager _projectManager;

        public QuanAppService(
            IRepository<Quan, int> quanRepository,
            IRepository<UserQuan, int> userQuanRepository,
            IRepository<ProjectQuan, int> projectQuanRepository,
            IRepository<TaskQuan, int> taskQuanRepository,
            ProjectManager projectManager)
        {
            _quanRepository = quanRepository;
            _taskQuanRepository = taskQuanRepository;
            _userQuanRepository = userQuanRepository;
            _projectQuanRepository = projectQuanRepository;
            _projectManager = projectManager;
        }

        public async Task<List<QuanDto.GetQuanTree>> GetQuanTree()
        {
            var list = await _quanRepository.GetAllListAsync();
            list = list.OrderBy(x => x.Sort).ToList();
            Dictionary<string, QuanDto.GetQuanTree> res = new Dictionary<string, QuanDto.GetQuanTree>();
            foreach (var item in list)
            {
                res.Add(item.Id.ToString(), new QuanDto.GetQuanTree()
                {
                    id = item.Id.ToString(),
                    text = item.Name,
                    code = item.Code,
                    expanded = false,
                    sort = item.Sort.ToString(),
                    parentId = item.ParentId.ToString(),
                    children = new List<QuanDto.GetQuanTree>(),
                    leaf = list.Any(x => x.ParentId == item.Id) ? false : true
                });
            }

            foreach (var item in res.Values)
            {
                if (res.ContainsKey(item.parentId.ToString()))
                {
                    res[item.parentId.ToString()].children.Add(item);
                }
            }

            var results = res.Values.Where(x => x.parentId == "0").ToList();

            return results;
        }


        public async Task CreateQuan(QuanDto.CreateQuanInPut input)
        {

            if (input.CurId > 0)
            {
                var q = await _quanRepository.GetAsync(input.CurId);
                q.Name = input.Name;
                await _quanRepository.UpdateAsync(q);
            }
            else
            {

                var lastChild = _quanRepository.GetAll().Where(x => x.ParentId == input.ParentId).OrderByDescending(x => x.Sort).FirstOrDefault();
                int sort = 1;
                if (lastChild != null)
                {
                    sort = lastChild.Sort + 1;
                }


                await _quanRepository.InsertAndGetIdAsync(new Quan()
                {
                    Name = input.Name,
                    Code = "",
                    Sort = sort,
                    ParentId = input.ParentId
                });
            }


            initQuanCode(input.ParentId);
        }


        public async Task MoveQuan(QuanDto.MoveQuanInPut input)
        {
            var moveTo = await _quanRepository.GetAsync(input.overId);

            var moveFrom = await _quanRepository.GetAsync(input.nodeId);
            switch (input.position)
            {
                case "before":
                    var moveChidren = _quanRepository.GetAll().Where(x => x.ParentId == moveTo.ParentId && x.Sort >= moveTo.Sort).ToList();
                    moveFrom.ParentId = moveTo.ParentId;
                    moveFrom.Sort = moveTo.Sort;
                    foreach (var item in moveChidren)
                    {
                        item.Sort = item.Sort + 1;
                    }
                    initQuanCode(moveTo.ParentId);
                    break;
                case "after":
                    var _moveChidren = _quanRepository.GetAll().Where(x => x.ParentId == moveTo.ParentId && x.Sort > moveTo.Sort).ToList();
                    moveFrom.ParentId = moveTo.ParentId;
                    moveFrom.Sort = moveTo.Sort + 1;
                    foreach (var item in _moveChidren)
                    {
                        item.Sort = item.Sort + 1;
                    }
                    initQuanCode(moveTo.ParentId);
                    break;
                case "append":
                    moveFrom.ParentId = moveTo.Id;
                    var lastnode = _quanRepository.GetAll().Where(x => x.ParentId == moveTo.Id).OrderByDescending(x => x.Sort).FirstOrDefault();
                    int sort = 1;
                    if (lastnode != null)
                    {
                        sort = lastnode.Sort + 1;
                    }
                    moveFrom.Sort = sort;
                    initQuanCode(moveTo.Id);
                    break;
                default:
                    break;
            }



        }


        public async Task EditQuan(List<QuanDto.EditQuanInPut> input)
        {
            foreach (var item in input)
            {
                var q = await _quanRepository.GetAsync(item.Id);
                q.Code = item.Code;
                q.Sort = item.Sort;
                q.Name = item.Name;
            }
            initQuanCode(0);
        }


        /// <summary>
        /// 重新初始化quan的Code
        /// </summary>
        private void initQuanCode(int parentId = 0)
        {
            

            var lst = _quanRepository.GetAll().ToList();


            List<int> toAddVals = new List<int>() { parentId };
            int rowIndex = 0;
            string PreCode = "";
            do
            {
                List<int> addedVals = new List<int>();
                foreach (var pId in toAddVals)
                {
                    rowIndex = 0;
                    PreCode = "";
                    if (pId > 0)
                    {
                        PreCode = lst.Where(x => x.Id == pId).Single().Code;
                    }



                    var _lst = lst.Where(x => x.ParentId == pId).OrderBy(x=>x.Sort).ToList();
                    foreach (var item in _lst)
                    {
                        item.Code = PreCode + rowIndex.ToString("00");
                        rowIndex++;
                        addedVals.Add(item.Id);
                    }

                }
                toAddVals = addedVals;
            } while (toAddVals.Count > 0);


           var userQuanlst= _userQuanRepository.GetAll();
           foreach (var item in userQuanlst)
           {
               var quan= lst.Where(x => x.Id == item.QuanId).FirstOrDefault();
               if (quan != null)
               {
                   item.QuanCode = quan.Code;
               }
               else
               {
                   item.QuanCode = "";
               }
               
           }


           var proQuanlst =_projectQuanRepository.GetAll();
           foreach (var item in proQuanlst)
           {
               var quan = lst.Where(x => x.Id == item.QuanId).FirstOrDefault();
               if (quan != null)
               {
                   item.QuanCode = quan.Code;
               }
               else
               {
                   item.QuanCode = "";
               }

           }


           var taskQuanlst =_taskQuanRepository.GetAll();
           foreach (var item in taskQuanlst)
           {
               var quan = lst.Where(x => x.Id == item.QuanId).FirstOrDefault();
               if (quan != null)
               {
                   item.QuanCode = quan.Code;
               }
               else
               {
                   item.QuanCode = "";
               }

           }

        }





        public Task GetQuanUser()
        {
            throw new NotImplementedException();
        }

        public List<GetUserQuanOutPut> GetQuanUser(int quanId)
        {
            List<GetUserQuanOutPut> results = new List<GetUserQuanOutPut>();
            var userQuan = _userQuanRepository.GetAll().Where(x => x.QuanId == quanId).ToList();
            foreach (var item in userQuan)
            {
                var user = UserManager.Users.Where(x => x.Id == item.UserId).SingleOrDefault();
                results.Add(new GetUserQuanOutPut()
                {
                    Id = item.Id,
                    Name = user.Name,
                    QuanId = quanId,
                    UserId = user.Id,
                    UserName = user.UserName
                });
            }
            return results;
        }


        public async Task SetQuanUser(QuanDto.SetQuanUserInPut input)
        {
            var q = _quanRepository.Get(input.QuanId);
            await _userQuanRepository.InsertAsync(new UserQuan()
            {
                QuanId = input.QuanId,
                UserId = input.UserId,
                QuanCode = q.Code
            });
        }


        public async Task RemoveQuanUser(IdInput<int> input)
        {
            await _userQuanRepository.DeleteAsync(input.Id);
        }


        public List<GetQuanCheckedTree> GetProjectQuan(int projectId)
        {
            var users = _projectManager.projectTeamRepository.GetAll().Where(x => x.IsDeleted == false && x.ProjectId == projectId).Select(q => q.UserId).ToList();

            var userQuans = _userQuanRepository.GetAll().Where(x => users.Contains(x.UserId)).ToList();


            var projectQuansIds = _projectQuanRepository.GetAll().Where(x => x.ProjectId == projectId).Select(x => x.QuanId).ToList();
            var list = _quanRepository.GetAll().OrderBy(x => x.Sort).ToList();
            var projectQuanCodes = list.Where(x => projectQuansIds.Contains(x.Id)).Select(x => x.Code).ToList();

            Dictionary<string, QuanDto.GetQuanCheckedTree> res = new Dictionary<string, QuanDto.GetQuanCheckedTree>();
            foreach (var item in list)
            {
                var uIds = userQuans.Where(x => x.QuanId == item.Id).Select(m => m.UserId);
                var names = UserManager.Users.Where(m => uIds.Contains(m.Id)).Select(q => q.Name);

                string text = item.Name;
                if (names.Count() > 0)
                {
                    text = text + "(" + string.Join(",", names) + ")";
                }

                res.Add(item.Id.ToString(), new QuanDto.GetQuanCheckedTree()
                {
                    id = item.Id.ToString(),
                    text = text,
                    IsUser = names.Count() > 0,
                    code = item.Code,
                    expanded = false,
                    @checked = projectQuansIds.Contains(item.Id) || projectQuanCodes.Any(x => x.Contains(item.Code)),
                    parentId = item.ParentId.ToString(),
                    children = new List<QuanDto.GetQuanCheckedTree>(),
                    leaf = list.Any(x => x.ParentId == item.Id) ? false : true
                });
            }

            foreach (var item in res.Values)
            {
                if (res.ContainsKey(item.parentId.ToString()))
                {
                    res[item.parentId.ToString()].children.Add(item);
                }
            }

            var results = res.Values.Where(x => x.parentId == "0").ToList();

            return results;
        }


        public async Task SetProjectQuan(SetProjectQuanInPut input)
        {
            await _projectQuanRepository.DeleteAsync(m => m.ProjectId == input.ProjectId);
            List<int> adds = new List<int>();

            foreach (var item in input.Array)
            {
                if (!input.Array.Any(x => x.Key == item.Value))
                {
                    adds.Add(item.Key);
                }
            }

            foreach (var quanId in adds)
            {
                var quan = _quanRepository.Get(quanId);
                await _projectQuanRepository.InsertAsync(new ProjectQuan()
                {
                    ProjectId = input.ProjectId,
                    QuanId = quanId,
                    QuanCode = quan.Code
                });
            }
        }


        public List<string> GetProjectQuanList(int projectId)
        {
            var users = _projectManager.projectTeamRepository.GetAll().Where(x => x.ProjectId == projectId).Select(q => q.UserId).ToList();
            var userQuans = _userQuanRepository.GetAll().Where(x => users.Contains(x.UserId)).ToList();
            var projectQuans = _projectQuanRepository.GetAll().Where(x => x.ProjectId == projectId).Select(x => x.QuanId).ToList();

            List<string> results = new List<string>();

            foreach (var quanId in projectQuans)
            {
                var uIds = userQuans.Where(x => x.QuanId == quanId).Select(m => m.UserId);
                var names = UserManager.Users.Where(m => uIds.Contains(m.Id)).Select(q => q.Name);
                var quan = _quanRepository.Get(quanId);

                string text = quan.Name;
                if (names.Count() > 0)
                {
                    text = text + "(" + string.Join(",", names) + ")";
                }
                results.Add(text);
            }
            return results;
        }


        public List<GetQuanCheckedTree> GetTaskQuan(int projectTaskId, string users)
        {
            List<long> _users = new List<long>();
            if (!string.IsNullOrEmpty(users))
            {
                _users = users.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => long.Parse(x)).ToList();
            }
            var taskQuanIds = _taskQuanRepository.GetAll().Where(x => x.TaskId == projectTaskId).Select(x => x.QuanId).ToList();

            var userQuans = _userQuanRepository.GetAll().Where(x => _users.Contains(x.UserId));

            var list = _quanRepository.GetAll().OrderBy(x => x.Sort).ToList();
            var taskQuanCodes = list.Where(x => taskQuanIds.Contains(x.Id)).Select(x => x.Code).ToList();
            Dictionary<string, QuanDto.GetQuanCheckedTree> res = new Dictionary<string, QuanDto.GetQuanCheckedTree>();
            foreach (var item in list)
            {
                var uIds = userQuans.Where(x => x.QuanId == item.Id).Select(m => m.UserId);
                var names = UserManager.Users.Where(m => uIds.Contains(m.Id)).Select(q => q.Name);

                string text = item.Name;
                if (names.Count() > 0)
                {
                    text = text + "(" + string.Join(",", names) + ")";
                }

                res.Add(item.Id.ToString(), new QuanDto.GetQuanCheckedTree()
                {
                    id = item.Id.ToString(),
                    text = text,
                    IsUser = names.Count() > 0,
                    code = item.Code,
                    expanded = false,
                    @checked = taskQuanIds.Contains(item.Id) || taskQuanCodes.Any(x => x.Contains(item.Code)),
                    parentId = item.ParentId.ToString(),
                    children = new List<QuanDto.GetQuanCheckedTree>(),
                    leaf = list.Any(x => x.ParentId == item.Id) ? false : true
                });
            }

            foreach (var item in res.Values)
            {
                if (res.ContainsKey(item.parentId.ToString()))
                {
                    res[item.parentId.ToString()].children.Add(item);
                }
            }

            var results = res.Values.Where(x => x.parentId == "0").ToList();

            return results;
        }


        public List<GetQuanCheckedTree> GetUserQuan(int userId)
        {

            var userQuans = _userQuanRepository.GetAll().Where(x => x.UserId == userId).Select(x => x.QuanId);

            var list = _quanRepository.GetAll().OrderBy(x => x.Sort).ToList();
            Dictionary<string, QuanDto.GetQuanCheckedTree> res = new Dictionary<string, QuanDto.GetQuanCheckedTree>();
            foreach (var item in list)
            {
                res.Add(item.Id.ToString(), new QuanDto.GetQuanCheckedTree()
                {
                    id = item.Id.ToString(),
                    text = item.Name,
                    code = item.Code,
                    expanded = false,
                    @checked = userQuans.Contains(item.Id),
                    parentId = item.ParentId.ToString(),
                    children = new List<QuanDto.GetQuanCheckedTree>(),
                    leaf = list.Any(x => x.ParentId == item.Id) ? false : true
                });
            }

            foreach (var item in res.Values)
            {
                if (res.ContainsKey(item.parentId.ToString()))
                {
                    res[item.parentId.ToString()].children.Add(item);
                }
            }

            var results = res.Values.Where(x => x.parentId == "0").ToList();

            return results;
        }


        public async Task RemoveQuan(IdInput<int> input)
        {
            await _quanRepository.DeleteAsync(input.Id);
        }
    }
}
